package com.site.util;

import com.site.common.TransactionUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/** Redisson分布式锁工具
 * author xiaochi
 * date 2024/8/2
 */
@Slf4j
@Component
public class LockUtil {
    private static long WAITTIME = 10;// 等待时间
    private static long LOCKRUNTIME = 5;// 持有锁时间

    private static final byte[] lock = new byte[0];

    private static String lockKey = "API-LOCK";
    private static RedissonClient redissonClient;

    @Autowired
    public void setRedissonClient(RedissonClient redissonClient) {
        LockUtil.redissonClient = redissonClient;
        log.info("LockUtil init finish.");
    }

    public static RedissonClient getRedissonClient() {
        return redissonClient;
    }

    /**
     * synchronized 加锁执行
     */
    public static void runSynchronized(Runnable runnable){
        synchronized (lock){
            runnable.run();
        }
    }

    /**
     * redission 加锁执行
     */
    public static RedissonClient run(Runnable runnable){
        return run(lockKey,runnable);
    }

    /**
     * Redis分布式加锁执行
     * @param lockKey 锁key
     * @param runnable supplier
     * @return
     */
    public static RedissonClient run(String lockKey, Runnable runnable){
        return run(lockKey,WAITTIME,LOCKRUNTIME,TimeUnit.SECONDS,runnable);
    }

    /**
     * Redis分布式加锁执行
     * @param lockKey 锁key
     * @param lockRunTime 加锁时间
     * @param runnable runnable
     * @return
     */
    public static RedissonClient run(String lockKey,long lockRunTime, Runnable runnable){
        return run(lockKey,WAITTIME,lockRunTime,TimeUnit.SECONDS,runnable);
    }

    /**
     * Redis分布式加锁执行
     * @param lockKey 锁key
     * @param waitGetLockTime 获取锁的等待时间
     * @param lockRunTime 加锁时间
     * @param runnable runnable
     * @return
     */
    public static RedissonClient run(String lockKey,long waitGetLockTime,long lockRunTime, Runnable runnable){
        return run(lockKey,waitGetLockTime,lockRunTime,TimeUnit.SECONDS,runnable);
    }

    /**
     * Redis分布式加锁执行
     * @param lockKey 锁key
     * @param waitGetLockTime 获取锁的等待时间
     * @param lockRunTime 加锁时间
     * @param timeUnit 时间单位
     * @param runnable runnable
     * @return
     */
    public static RedissonClient run(String lockKey,long waitGetLockTime,long lockRunTime, TimeUnit timeUnit,Runnable runnable){
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(waitGetLockTime,lockRunTime, timeUnit)){
                runnable.run();
            }
        }catch (Exception e){
            //log.info("LockUtil Runnable执行异常,{}",e);抛出异常是为了捕获提示信息返回给前端
            throw new IllegalArgumentException(e.getMessage());
        }finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
        return redissonClient;
    }

    //================================= boolean返回值 =============================

    /**
     * redission 加锁执行
     */
    public static boolean run(Supplier<Boolean> supplier){
        return run(lockKey,supplier);
    }

    /**
     * 加锁加事务执行
     * @param supplier
     */
    public static boolean runTransaction(Supplier<Boolean> supplier){
        return run(lockKey,() -> TransactionUtil.execute(() -> {
            try {
                return supplier.get();
            }catch (Exception e){
                log.info("LockUtil加锁事务执行异常,{}",e);
                return false;
            }
        }));
    }

    /**
     * Redis分布式加锁执行
     * @param lockKey 锁key
     * @param supplier supplier
     * @return
     */
    public static boolean run(String lockKey, Supplier<Boolean> supplier){
        return run(lockKey,WAITTIME,LOCKRUNTIME,TimeUnit.SECONDS,supplier);
    }

    /**
     * Redis分布式加锁执行
     * @param lockKey 锁key
     * @param lockRunTime 加锁时间
     * @param supplier supplier
     * @return
     */
    public static boolean run(String lockKey,long lockRunTime, Supplier<Boolean> supplier){
        return run(lockKey,WAITTIME,lockRunTime,TimeUnit.SECONDS,supplier);
    }

    /**
     * Redis分布式加锁执行
     * @param lockKey 锁key
     * @param waitGetLockTime 获取锁的等待时间
     * @param lockRunTime 加锁时间
     * @param supplier run
     * @return
     */
    public static boolean run(String lockKey,long waitGetLockTime,long lockRunTime, Supplier<Boolean> supplier){
        return run(lockKey,waitGetLockTime,lockRunTime,TimeUnit.SECONDS,supplier);
    }

    /**
     * Redis分布式加锁执行
     * @param lockKey 锁key
     * @param waitGetLockTime 获取锁的等待时间
     * @param lockRunTime 加锁时间
     * @param timeUnit 时间单位
     * @param supplier supplier
     * @return
     */
    public static boolean run(String lockKey,long waitGetLockTime,long lockRunTime, TimeUnit timeUnit,Supplier<Boolean> supplier){
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(waitGetLockTime,lockRunTime, timeUnit)){
                return supplier.get();
            }
        }catch (Exception e){
            //log.info("LockUtil Supplier执行异常,{}",e); 抛出异常是为了捕获提示信息返回给前端
            throw new IllegalArgumentException(e.getMessage());
        }finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()){
                lock.unlock();
            }
        }
        return false;
    }
}